package org.NooLab.texx.components;

import java.io.ByteArrayInputStream;

import java.io.Serializable;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;

import org.NooLab.utilities.logging.LogControl;
import org.NooLab.utilities.logging.PrintLog;
import org.NooLab.utilities.net.GUID;


import org.NooLab.structures.DocumentMetaData;
import org.NooLab.structures.texx.plugg.algo.intf.AlgoReaderIntf;
import org.NooLab.structures.texx.plugg.algo.intf.AlgoSourceDescription;
import org.NooLab.structures.texx.plugg.algo.intf.AlgorithmIntf;
import org.NooLab.texx.*;

import org.NooLab.texx.properties.TexxAppGeneralPropertiesIntf;
import org.NooLab.texx.properties.TexxProperties;
import org.NooLab.texx.tcp.TikaServerConnection;
import org.NooLab.texxplugg.tika.TikaReader;





public class WorkDataObject 
								implements 
											Serializable,
											Observer,
											//	used for read access, e.g. by nodes and other applications
											DataSourceIntf,
											//  all objects that need to be storable should implement this interface
											PersistentAgentIntf{

	
	private static final long serialVersionUID = 2460255010695386472L;

	transient TexxProperties texxProperties;
	transient TexxFactory texxFactory;
	
	PrintLog out;

	private int index = -1;

	String sourceUrl = "";
	long sourceId  =0L;
	
	/**
	 * the plain text as extracted from the source 
	 */
	String rawPlainText = "" ;
	DocumentMetaData documentMetaData;
	
	/**
	 * the acceptance receipt returned by the algorithm, not used here, but suitable for externalized referenced storage
	 */
	String receipt = "" ;
	
	Long timestamp = 0L;
	public String fileReceiptGuid;
	private boolean isFinished;
	private String tikasrvTextData;
	private int tikasrvReturn;

	private boolean useDetailedOfficeView=false; // TODO: later as part of global properties
	
	// ========================================================================
	public WorkDataObject(TexxProperties props) {
		// 
		texxProperties = props;
		receipt = GUID.randomvalue();
		out = texxProperties.getFileOrganizer().getOut() ;
	}
	
	public WorkDataObject(WorkDataObject inObj, boolean keepReceipt) {
		
		
		if (inObj==null){
			return;
		}
		
		texxProperties = inObj.texxProperties ;
		texxFactory = inObj.texxFactory ;
		
		out = texxProperties.getFileOrganizer().getOut() ;
		
		index = inObj.index ;
		sourceUrl = inObj.sourceUrl ;
		sourceId = inObj.sourceId;
		
		rawPlainText = inObj.rawPlainText ;
		if (keepReceipt){
			receipt = inObj.receipt ;
		}else{
			receipt = GUID.randomvalue();
		}
		
		timestamp = inObj.timestamp ;
		fileReceiptGuid = inObj.fileReceiptGuid ;
		
	}
	// ========================================================================	
	
	public void importData(DataReceptor dataReceptor, int iflag){
		
		TikaReader reader;
		
		// 
		try {
			
			reader = TikaReader.class.newInstance();
			rawPlainText = readDocument(dataReceptor,(AlgoReaderIntf)reader);
			
			
		} catch (InstantiationException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		}
		
	}
	
	synchronized public int importDataByTikaServer(DataReceptor dataReceptor, int iflag){
	// as long as we operate 
			
			
			String filename,sendingGuid="";
			int textLen=0;
			long startingTime=0L , returnTime=0L, timeNeeded=-1L ;
			
			TikaServerConnection tsc = new TikaServerConnection(this, texxFactory, true);
			
			tsc.setWaitingMode( TikaServerConnection._TCP_CLIENT_WAITING_MODE_COMPLETION );
			
			tikasrvReturn = -99 ;
			try {
				filename = dataReceptor.getLoadedFileName() ;
				
				startingTime = System.currentTimeMillis() ;
				sendingGuid = tsc.send(filename); // "D:/kwa/writing/doc/biodiv.doc");  
							  if (sendingGuid.length()>0){
								  
							  }
							  
			} catch (Exception e) {
				// e.g., if server does not exist, (re-raising?)
				return -3;
			}
			
			if (tikasrvReturn == -99){
				out.print(2, "waiting loop after send, before receiving results (a= ...");
			}
			int zz=0; // waiting 120 seconds... should be enough, if not, the TikaServer will send "busy"
			while ((zz<100*120) &&(tikasrvReturn == -99)){
				out.delay(10); zz++;
				if (zz%100==0){
					// check tikaserver for being reachable and busy... 
					// == time since the last busy response should be <2000millis
				}
				 
			}
			
			returnTime = System.currentTimeMillis() ;
			timeNeeded = returnTime - startingTime ;
				
			String mime = "";
			if (documentMetaData!=null){
				documentMetaData.getMimeType();
			}
			if ( (mime.length()>0)){
				if ((useDetailedOfficeView) && (mime.toLowerCase().contains("doc"))){
					// if document is Microsoft Office, analyze doc by Apache POI 
				}
			}
			String text = tikasrvTextData;
			out.print(3, "\n...returned from TikaConnection after "+timeNeeded+"ms, data (len:"+text.length()+") is : \n");
			
			rawPlainText = tikasrvTextData;
			
			if ((rawPlainText!=null) && (rawPlainText.length()>0)){
				textLen = rawPlainText.length(); 
			}
			out.delay(100);
			
			tsc.disconnect() ;
			
			out.delay(150);
			tsc = null;
			return textLen ; 
	}
		
		
	@Override
	public void update(Observable sender, Object objText) {
		String text = "";
		
		
		if (objText instanceof String){
			text = (String)objText;
			// this text may come as XML!!
			if (text.trim().startsWith("<?xml version=\"1.0\"")){
				
				TikaServerResults tsr = new TikaServerResults(text);
				tikasrvTextData = tsr.go().getPlainText();
				documentMetaData = tsr.getMeta();
				
			}else{
				tikasrvTextData = text;
			}
		}
		
		out.print(2, "message received by WDO, adjusting flags...");
		
		tikasrvReturn = 1;
	}

	public void importDataByPlugin(DataReceptor dataReceptor, int iflag) throws Exception {
	
		RawFileData rawFileData;
		String urlstring ="";
		ByteArrayInputStream inValues ;
		// inValues = String to stream
	
		String text = "" ,version ="";
		
		rawFileData = dataReceptor.getRawFileData();
		long calctimestart =0;
		
		AlgoReaderIntf reader=null;
		AlgorithmsProviderIntf algoProvider ;
	  	TexxPluginSettingsIntf pluginSettings;
		TexxAppGeneralPropertiesIntf texAppProperties;
		pluginSettings = texxProperties.getPluginSettings() ;
		
		Class clzz=null ;
		if (pluginSettings == null){
			throw(new Exception("Plugin requested for importing document, but pluginsettings are not available.")) ;
		}
		                                	out.print(2,"going to read the document via reader-plugin (1)...");
		if (pluginSettings != null){
											out.print(2,"going to read the document via reader-plugin (2)...");			
			algoProvider = pluginSettings.getAlgorithmsProviderByType(AlgorithmIntf._ALGOTYPE_READER) ;
		
			// we need mimetype property in the catalog.xml
			// selecting the plugin for the mimetype
			
			// document 
			
			if (algoProvider!=null){
											out.print(2,"going to read the document via reader-plugin (3)...");

			    
				
				Object algo = null ;
				Map<String, Object> algoMap = algoProvider.getAlgorithMap() ;
				
				
				
				if ((algoMap != null) && (algoMap.containsKey("PdfReader"))){
					// algo = algoMap.get("PdfReader");
				}

				if ((algoMap != null) && (algoMap.containsKey("TikaReader"))){
					algo = algoMap.get("TikaReader");
				}
											out.print(2,"going to read the document via reader-plugin (4)...");
				if (algo!=null){
					try{ 
						reader = ((AlgoReaderIntf) algo).getClass().newInstance();
						
								String _reader_details ="";
								if (reader!=null){
									_reader_details = reader.toString().replace("org.NooLab.", "");
								}else{
									_reader_details = null;
								}
						out.print(2,"going to read the document via reader-plugin (5), reader is "+(_reader_details)+"...");

						rawPlainText = readDocument(dataReceptor,(AlgoReaderIntf)reader) ;					
						
					}catch(Exception e){
						e.printStackTrace();
					}
				}
				// log4j:WARN No appenders could be found for logger (org.apache.pdfbox.util.PDFStreamEngine).
				// out.printErr(2, "\nReader : "+version +"\n"+rawPlainText) ;
				
			} // ?
			
		} // pluginSettings  ?
		
	}


	private String readDocument(DataReceptor dataReceptor, AlgoReaderIntf reader) {
		 
		Long calctimestart = System.currentTimeMillis() ;
		String urlstring="",version="";

		try {

			AlgoSourceDescription sourceDescription = new AlgoSourceDescription();

			urlstring = dataReceptor.getLoadedFileName();

			sourceDescription.setUrlstring(urlstring);
			calctimestart = System.currentTimeMillis();
			receipt = reader.setDataDescription(sourceDescription);
			/*
			 * // Logger.getRootLogger().setLevel(Level.INFO);
			 * Logger.getRootLogger().setLevel(Level.ERROR); Logger lgg =
			 * Logger.getLogger("org.NooLab.texxplugg");
			 * LogControl.cLogger.setLogging( "org.apache.tika" );
			 * LogControl.cLogger.setLogging( "org.NooLab.texxplugg" );
			 * 
			 * 
			 * lgg = Logger.getRootLogger(); lgg.setLevel(Level.ERROR);
			 * 
			 * lgg.removeAllAppenders() ;
			 */
						out.print(2, "starting extracting cores ...");
			reader.calculate();
			// we need a progress indicator ... and several docs in parallel ...
			// and not output to console ...
			version = reader.getVersion();

			boolean hb = false;

			hb = reader.performPostProcessing();
		} catch (Exception e) {
			// java.lang.AbstractMethodError ???
			if (LogControl.Level >= 2) {
				e.printStackTrace();
			}
		}
						out.print(2, "going to read the document via reader-plugin (6)...");
		rawPlainText = reader.getText();
		String mimeType = reader.getDocTypeMime(); // either mime (Tika) or
													// extension or similar

		long calctimefinish = System.currentTimeMillis();
		long calctime = calctimefinish - calctimestart;

		sourceUrl = urlstring;
		timestamp = System.currentTimeMillis();

		if ((rawPlainText.length() > 100) && (calctime > 1)) { // CONSTANT
																// minimum
																// length ...

			// postprocessing: concatenate hyphenated words
			// numbers in the text: footnotes/endnotes dunne point out.15
			// create a document which creates the context

						out.print(2, "document read via reader-plugin (6.A), length is approx. " + 
									  rawPlainText.length()+ " chars ...");

		} else {
						out.print(2, "going to read the document via reader-plugin (6.B)...");
						out.print(2, "document was too short (<100 characters)");

			rawPlainText = "";
			sourceUrl = "";
			timestamp = 0L;
		}

		if (reader != null) {
			reader.clear();
			reader = null;
		}

		return rawPlainText;
	}

	public String save( int format) {
		// 1 as xml, 2 = bin
		String filereceipt = GUID.randomvalue() ;
		
		
		
		
		return filereceipt;
	}


	public void prepare() {
		// 
		
	}

	public void setIndex(int ix) {
		// 
		index = ix;
	}


	public int getIndex() {
		return index;
	}


	public void setFactory(TexxFactory factory) {
		texxFactory = factory;
	}


	public TexxFactory getTexxFactory() {
		return texxFactory;
	}


	public void setTexxFactory(TexxFactory texxFactory) {
		this.texxFactory = texxFactory;
	}


	public TexxProperties getTexxProperties() {
		return texxProperties;
	}


	public void setTexxProperties(TexxProperties texxProperties) {
		this.texxProperties = texxProperties;
	}


	public String getRawPlainText() {
		if (rawPlainText==null){
			rawPlainText="";
		}
		return rawPlainText;
	}


	public void setRawPlainText(String rawPlainText) {
		this.rawPlainText = rawPlainText;
	}
	public DocumentMetaData getDocumentMetaData() {
		return documentMetaData;
	}

	public String getSourceUrl() {
		return sourceUrl;
	}


	public void setSourceUrl(String source_url) {
		sourceUrl = source_url;
	}

	public void setSourceId(long did) {
		 
		sourceId = did;
	}


	public long getSourceId() {
		return sourceId;
	}

	public String getReceipt() {
		return receipt;
	}


	// ========================================================================	
	
		
	public void setReceipt(String receipt) {
		this.receipt = receipt;
	}


	public void setOut(PrintLog out) {
		this.out = out;
	}


	public PrintLog getOut() {
		// 
		return out;
	}

	public long getTimeStamp() {
		
		return timestamp;
	}

	public void setFinished(boolean flag) {

		isFinished = flag;
	}

	public boolean isFinished() {
		return isFinished;
	}

	public String getFileReceiptGuid() {
		return fileReceiptGuid;
	}

	public void setFileReceiptGuid(String fileReceiptGuid) {
		this.fileReceiptGuid = fileReceiptGuid;
	}

	

}
